<#include "license.ftl">
<@license/>
<#assign object = doc.object>
package ${object.@package}.businessrules.base;

import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
<#if doc["/object/attributes/*[@regexp]"][0]??>
import java.util.regex.Matcher;
import java.util.regex.Pattern;
</#if>
import redora.service.BusinessRuleViolation;
import redora.service.BusinessRuleViolation.Action;
import redora.service.BusinessRuleViolation.StandardRule;
import redora.exceptions.BusinessRuleViolationException;
import redora.exceptions.RedoraException;

import ${object.@package}.businessrules.*;
import ${object.@package}.model.*;
import ${object.@package}.model.fields.${object.@name}Fields;

/**
* Generated business rules implementation. The business rules are located in
* the onInsert, onUpdate and onDelete method. Standard rules are in this class,
* custom rules should be implemented in the ${object.@name}BusinessRules class.
* @see StandardRule
* @author Redora (www.redora.net)
*/
public abstract class ${object.@name}BusinessRulesBase {
    static final transient Logger l = Logger.getLogger("${object.@package}.service.base.${object.@name}BusinessRulesBase");

<#list doc["/object/attributes/*[@regexp]"] as att>
    <#if att?node_name == "date">
    final static Pattern ${att.@fieldName}Pattern = Pattern.compile("${att.@regexp}");
    <#elseif att?node_name == "string">
    final static Pattern ${att.@fieldName}Pattern = Pattern.compile("${att.@regexp}");
    </#if>
</#list>

<#list doc["/object/businessRules/businessRule"] as br>
    /** ${br.@javadoc} */
    public static final int BR_${br.@number} = ${br.@number};
</#list>
    @NotNull
    private static Set<BusinessRuleViolation> onAll(@NotNull ${object.@name} pojo, @NotNull Action action)
            throws BusinessRuleViolationException {
        Set<BusinessRuleViolation> retVal = new HashSet<BusinessRuleViolation>();
<#list object.formScope?children as att>
    <#if att?node_type == "element">
        <#if att.@notnull[0]?? && att.@notnull == "true">
            <#if att?node_name == "string">
        if (pojo.${att.@fieldName} == null || pojo.${att.@fieldName}.trim().length() == 0) {
            retVal.add(new BusinessRuleViolation(
            pojo, ${object.@name}Fields.${att.@fieldName}, StandardRule.NotNull.ruleId, action));
        }
        <#elseif att?node_name == "object">
        if (pojo.${att.@fieldName}Id == null) {
            retVal.add(new BusinessRuleViolation(
                pojo, ${object.@name}Fields.${att.@fieldName}Id, StandardRule.NotNull.ruleId, action));
        }
        <#elseif att?node_name != "object">
        if (pojo.${att.@fieldName} == null) {
            retVal.add(new BusinessRuleViolation(
                pojo, ${object.@name}Fields.${att.@fieldName}, StandardRule.NotNull.ruleId, action));
        }
        </#if>
    </#if>
    <#if att.@regexp[0]??>
        if (pojo.dirty.containsKey(${object.@name}Fields.${att.@fieldName}) && pojo.${att.@fieldName} != null) {
        <#if att?node_name == "date" || att?node_name == "datetime">
            try {
                Matcher ${att.@fieldName}Matcher = ${att.@fieldName}Pattern.matcher(redora.db.SQLParameter.yyyyMMddHHMMSS.format(pojo.${att.@fieldName}));
                if (!${att.@fieldName}Matcher.matches()) {
                    retVal.add(new BusinessRuleViolation(pojo, ${object.@name}Fields.${att.@fieldName}
                        , StandardRule.MatchRegexp.ruleId, action));
                }
            } catch(Exception e) {
                l.log(SEVERE, "Failed to check date ${att.@fieldName}'s for regexp ${att.@regexp} ", e);
                throw new BusinessRuleViolationException("Failed to check date ${att.@fieldName}'s regexp ${att.@regexp}",e);
            }
        <#elseif att?node_name == "string">
            Matcher ${att.@name}Matcher = ${att.@name}Pattern.matcher(pojo.${att.@fieldName});
            if (!${att.@fieldName}Matcher.matches()) {
                retVal.add(new BusinessRuleViolation(pojo, ${object.@name}Fields.${att.@fieldName}
                    , StandardRule.MatchRegexp.ruleId, action));
            }
        <#else>
            HOLA: unspecified regexp in ${att.@name}. Check the model, XSD or fix this template
        </#if>
        }
    </#if>
    <#if att.@maxlength[0]??>
        if (pojo.dirty.containsKey(${object.@name}Fields.${att.@fieldName}) && pojo.${att.@fieldName} != null && pojo.${att.@fieldName}.length() > ${att.@maxlength}) {
            ArrayList<Object> param = new ArrayList<Object>();
            param.add(${att.@maxlength});
            retVal.add(new BusinessRuleViolation(pojo, ${object.@name}Fields.${att.@fieldName}, StandardRule.MaxLength.ruleId, action, param));
        }
    </#if>
</#if>
</#list>

        return retVal;
    }

    /**
    * Checks if any business rules are violated for ${object.@name} and possible related
    * children that are (also) changed.<br>
    * Normally you don't need this method, it is invoked by ${object.@name}Service.persist(${object.@name}),
    * but you might sometimes want a sneak preview on violated business rule violations.
    * @param pojo (Mandatory)
    * @param when (Mandatory)
    * @return Empty list when OK, else a list of violations.
    */
    @NotNull
    public static Set<BusinessRuleViolation> check(@NotNull ${object.@name} pojo, @NotNull BusinessRuleViolation.Action when)
                throws RedoraException {
        Set<BusinessRuleViolation> retVal = new HashSet<BusinessRuleViolation>();
        if (when == BusinessRuleViolation.Action.Delete) {
            retVal.addAll(${object.@name}BusinessRules.onDelete(pojo));
        } else if (when == BusinessRuleViolation.Action.Insert) {
            retVal.addAll(${object.@name}BusinessRules.onInsert(pojo));
        } else {
            retVal.addAll(${object.@name}BusinessRules.onUpdate(pojo));
        }

<#list doc["/object/attributes/set[@multiplicity='1-to-n']"] as att>
    <#assign finderName = att.@myName>
    <#if att.@class == object.@name>
        <#assign finderName = att.@theirName>
    </#if>
        if (pojo.${att.@plural}IsRetrieved()) {
            for (${att.@class} child : pojo.get${att.@plural?cap_first}()) {
                child.set${finderName?cap_first}(pojo);
                if (when == BusinessRuleViolation.Action.Insert) {
                    //make sure the not-null constraint is not violated, it will be reset on persist()
                    child.set${finderName?cap_first}Id(-1L);
                }
                if (when == BusinessRuleViolation.Action.Delete) {
                    retVal.addAll(${att.@class}BusinessRules.check(child
                        , BusinessRuleViolation.Action.Delete));
                } else {
                    retVal.addAll(${att.@class}BusinessRules.check(child
                        , child.isNew ? BusinessRuleViolation.Action.Insert : BusinessRuleViolation.Action.Update));
                }
            }
            for (${att.@class} delete : pojo.get${att.@plural?cap_first}().getRemovedObjects()) {
                retVal.addAll(${att.@class}BusinessRules.check(delete, BusinessRuleViolation.Action.Delete));
            }
        }
</#list>

        return retVal;
    }

    @NotNull
    public static Set<BusinessRuleViolation> onInsert(@NotNull ${object.@name} pojo) throws BusinessRuleViolationException {
        return onAll(pojo, Action.Insert);
    }
    @NotNull
    public static Set<BusinessRuleViolation> onUpdate(@NotNull ${object.@name} pojo) throws BusinessRuleViolationException {
        return onAll(pojo, Action.Update);
    }
    @NotNull
    public static Set<BusinessRuleViolation> onDelete(@NotNull ${object.@name} pojo) throws BusinessRuleViolationException {
        return new HashSet<BusinessRuleViolation>();
    }
}
